using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using BanZuiCloudControlAgent.Core.Mqtt.Models;
using BanZuiCloudControlAgent.Utils.Common;
using BanZuiCloudControlAgent.Utils.Database.Models;
using BanZuiCloudControlAgent.Utils.Logging;
using Dapper;

namespace BanZuiCloudControlAgent.Utils.Database.Repositories
{
    /// <summary>
    /// MQTT消息仓储，负责消息的存储和查询
    /// </summary>
    public class MqttMessageRepository
    {
        private readonly Logger _logger = LogManager.GetLogger(nameof(MqttMessageRepository));
        
        /// <summary>
        /// 最大失败次数，超过此次数的消息将不再处理
        /// </summary>
        private const int MAX_FAIL_COUNT = 2;
        
        /// <summary>
        /// 创建数据库连接，包含异常处理
        /// </summary>
        /// <returns>数据库连接，如果创建失败则返回null</returns>
        private IDbConnection TryCreateConnection()
        {
            try
            {
                return DbConnectionFactory.CreateConnection();
            }
            catch (Exception ex)
            {
                _logger.Error("创建数据库连接失败", ex);
                return null;
            }
        }
        
        /// <summary>
        /// 保存消息
        /// </summary>
        /// <param name="message">MQTT消息</param>
        /// <returns>是否保存成功</returns>
        public async Task<bool> SaveMessageAsync(BaseMessageModel message)
        {
            try
            {
                if (message == null)
                {
                    _logger.Warn("保存消息失败：消息为空");
                    return false;
                }
                
                // 将消息负载转换为JSON字符串
                string payloadJson = null;
                if (message.Payload != null)
                {
                    payloadJson = JsonHelper.Serialize(message.Payload);
                }
                
                // 创建数据对象
                var messageDO = MqttMessageDO.FromBaseMessage(message, payloadJson);
                
                using (var connection = TryCreateConnection())
                {
                    if (connection == null)
                    {
                        return false;
                    }
                    
                    connection.Open();
                    
                    // 检查消息是否已存在
                    var existingMessage = await connection.QueryFirstOrDefaultAsync<MqttMessageDO>(
                        "SELECT Id, Status, FailCount FROM MqttMessages WHERE MessageId = @MessageId",
                        new { MessageId = message.MessageId });
                        
                    if (existingMessage != null)
                    {
                        _logger.Debug($"消息已存在，MessageId: {message.MessageId}, Status: {existingMessage.Status}, FailCount: {existingMessage.FailCount}");
                        return true; // 消息已存在，视为保存成功
                    }
                    
                    // 插入消息
                    var sql = @"
                        INSERT INTO MqttMessages 
                        (MessageId, MessageType, Timestamp, DeviceCode, Payload, Status, FailCount, LastProcessTime, CreateTime) 
                        VALUES 
                        (@MessageId, @MessageType, @Timestamp, @DeviceCode, @Payload, @Status, @FailCount, @LastProcessTime, @CreateTime)";
                        
                    var result = await connection.ExecuteAsync(sql, messageDO);
                    
                    _logger.Debug($"保存消息成功，MessageId: {message.MessageId}, MessageType: {message.MessageType}");
                    return result > 0;
                }
            }
            catch (Exception ex)
            {
                _logger.Error($"保存消息失败: {ex.Message}", ex);
                return false;
            }
        }
        
        /// <summary>
        /// 检查消息是否可以处理
        /// </summary>
        /// <param name="messageId">消息ID</param>
        /// <returns>是否可以处理</returns>
        public async Task<bool> CanProcessMessageAsync(string messageId)
        {
            try
            {
                if (string.IsNullOrEmpty(messageId))
                {
                    _logger.Warn("检查消息是否可以处理失败：消息ID为空");
                    return false;
                }
                
                using (var connection = TryCreateConnection())
                {
                    if (connection == null)
                    {
                        return false;
                    }
                    
                    connection.Open();
                    
                    var message = await connection.QueryFirstOrDefaultAsync<MqttMessageDO>(
                        "SELECT Status, FailCount FROM MqttMessages WHERE MessageId = @MessageId",
                        new { MessageId = messageId });
                        
                    if (message == null)
                    {
                        // 消息不存在，可以处理
                        return true;
                    }
                    
                    // 如果消息状态为处理完成，或者失败次数超过最大值，则不再处理
                    if (message.Status == (int)MessageStatus.Completed || 
                        (message.Status == (int)MessageStatus.Failed && message.FailCount >= MAX_FAIL_COUNT))
                    {
                        return false;
                    }
                    
                    return true;
                }
            }
            catch (Exception ex)
            {
                _logger.Error($"检查消息是否可以处理失败: {ex.Message}", ex);
                return false;
            }
        }
        
        /// <summary>
        /// 标记消息为处理完成
        /// </summary>
        /// <param name="messageId">消息ID</param>
        /// <returns>是否标记成功</returns>
        public async Task<bool> MarkMessageAsCompletedAsync(string messageId)
        {
            try
            {
                if (string.IsNullOrEmpty(messageId))
                {
                    _logger.Warn("标记消息为处理完成失败：消息ID为空");
                    return false;
                }
                
                using (var connection = TryCreateConnection())
                {
                    if (connection == null)
                    {
                        return false;
                    }
                    
                    connection.Open();
                    
                    var result = await connection.ExecuteAsync(
                        @"UPDATE MqttMessages 
                          SET Status = @Status, 
                              ProcessedTime = @ProcessedTime, 
                              LastProcessTime = @LastProcessTime 
                          WHERE MessageId = @MessageId",
                        new { 
                            MessageId = messageId, 
                            Status = (int)MessageStatus.Completed, 
                            ProcessedTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"),
                            LastProcessTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")
                        });
                        
                    return result > 0;
                }
            }
            catch (Exception ex)
            {
                _logger.Error($"标记消息为处理完成失败: {ex.Message}", ex);
                return false;
            }
        }
        
        /// <summary>
        /// 标记消息为处理失败
        /// </summary>
        /// <param name="messageId">消息ID</param>
        /// <returns>是否标记成功</returns>
        public async Task<bool> MarkMessageAsFailedAsync(string messageId)
        {
            try
            {
                if (string.IsNullOrEmpty(messageId))
                {
                    _logger.Warn("标记消息为处理失败失败：消息ID为空");
                    return false;
                }
                
                using (var connection = TryCreateConnection())
                {
                    if (connection == null)
                    {
                        return false;
                    }
                    
                    connection.Open();
                    
                    // 更新消息状态为失败，并增加失败次数
                    var result = await connection.ExecuteAsync(
                        @"UPDATE MqttMessages 
                          SET Status = @Status, 
                              FailCount = FailCount + 1, 
                              LastProcessTime = @LastProcessTime 
                          WHERE MessageId = @MessageId",
                        new { 
                            MessageId = messageId, 
                            Status = (int)MessageStatus.Failed, 
                            LastProcessTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")
                        });
                        
                    return result > 0;
                }
            }
            catch (Exception ex)
            {
                _logger.Error($"标记消息为处理失败失败: {ex.Message}", ex);
                return false;
            }
        }
        
        /// <summary>
        /// 获取未处理完成的消息列表
        /// </summary>
        /// <param name="messageType">消息类型，可选</param>
        /// <param name="limit">限制返回数量，默认100条</param>
        /// <returns>未处理完成的消息列表</returns>
        public async Task<List<MqttMessageDO>> GetUnprocessedMessagesAsync(string messageType = null, int limit = 100)
        {
            try
            {
                using (var connection = TryCreateConnection())
                {
                    if (connection == null)
                    {
                        return new List<MqttMessageDO>();
                    }
                    
                    connection.Open();
                    
                    string sql;
                    object param;
                    
                    if (string.IsNullOrEmpty(messageType))
                    {
                        sql = @"SELECT * FROM MqttMessages 
                                WHERE (Status = @ProcessingStatus OR 
                                      (Status = @FailedStatus AND FailCount < @MaxFailCount)) 
                                ORDER BY Id ASC LIMIT @Limit";
                        param = new { 
                            ProcessingStatus = (int)MessageStatus.Processing, 
                            FailedStatus = (int)MessageStatus.Failed,
                            MaxFailCount = MAX_FAIL_COUNT,
                            Limit = limit 
                        };
                    }
                    else
                    {
                        sql = @"SELECT * FROM MqttMessages 
                                WHERE (Status = @ProcessingStatus OR 
                                      (Status = @FailedStatus AND FailCount < @MaxFailCount)) 
                                AND MessageType = @MessageType 
                                ORDER BY Id ASC LIMIT @Limit";
                        param = new { 
                            ProcessingStatus = (int)MessageStatus.Processing, 
                            FailedStatus = (int)MessageStatus.Failed,
                            MaxFailCount = MAX_FAIL_COUNT,
                            MessageType = messageType, 
                            Limit = limit 
                        };
                    }
                    
                    var result = await connection.QueryAsync<MqttMessageDO>(sql, param);
                    return result.ToList();
                }
            }
            catch (Exception ex)
            {
                _logger.Error($"获取未处理完成的消息列表失败: {ex.Message}", ex);
                return new List<MqttMessageDO>();
            }
        }
        
        /// <summary>
        /// 清理旧消息
        /// </summary>
        /// <param name="completedDaysToKeep">已完成消息保留天数，默认30天</param>
        /// <param name="failedDaysToKeep">失败消息保留天数，默认7天</param>
        /// <returns>清理的消息数量</returns>
        public async Task<int> CleanupOldMessagesAsync(int completedDaysToKeep = 30, int failedDaysToKeep = 7)
        {
            try
            {
                using (var connection = TryCreateConnection())
                {
                    if (connection == null)
                    {
                        return 0;
                    }
                    
                    connection.Open();
                    
                    var completedCutoffDate = DateTime.Now.AddDays(-completedDaysToKeep).ToString("yyyy-MM-dd HH:mm:ss.fff");
                    var failedCutoffDate = DateTime.Now.AddDays(-failedDaysToKeep).ToString("yyyy-MM-dd HH:mm:ss.fff");
                    
                    var result = await connection.ExecuteAsync(
                        @"DELETE FROM MqttMessages 
                          WHERE (Status = @CompletedStatus AND ProcessedTime < @CompletedCutoffDate) OR
                                (Status = @FailedStatus AND LastProcessTime < @FailedCutoffDate AND FailCount >= @MaxFailCount)",
                        new { 
                            CompletedStatus = (int)MessageStatus.Completed, 
                            FailedStatus = (int)MessageStatus.Failed,
                            CompletedCutoffDate = completedCutoffDate,
                            FailedCutoffDate = failedCutoffDate,
                            MaxFailCount = MAX_FAIL_COUNT
                        });
                        
                    _logger.Info($"清理旧消息完成，共清理 {result} 条消息");
                    return result;
                }
            }
            catch (Exception ex)
            {
                _logger.Error($"清理旧消息失败: {ex.Message}", ex);
                return 0;
            }
        }
    }
} 